// Fill out your copyright notice in the Description page of Project Settings.


#include "Actor/EffectActorBase.h"


#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystem/AuraAttributeSet.h"

AEffectActorBase::AEffectActorBase()
{
	PrimaryActorTick.bCanEverTick = true;

	SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot")));
}


void AEffectActorBase::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> ApplyGameplayEffectClass)
{
	UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);

	if (TargetASC == nullptr)
	{
		return;
	}

	// 创建GEContext
	FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
	EffectContextHandle.AddSourceObject(this);

	// 创建GE实例
	const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(
		ApplyGameplayEffectClass,
		EffectSpecLevel,
		EffectContextHandle
	);

	// 应用GE
	const FActiveGameplayEffectHandle ActiveGameplayEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(
		*EffectSpecHandle.Data.Get()
	);

	// 检查效果的 Duration是否为Infinite,是的话把activeGEHandle加入map
	const bool bIsInfinite = EffectSpecHandle.Data.Get()->Def->DurationPolicy == EGameplayEffectDurationType::Infinite;

	if (bIsInfinite && InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		ActiveEffectToRemove.Add(ActiveGameplayEffectHandle, TargetASC);
	}
	else if (!bIsInfinite && bDestroyOnEffectApplication) // 如果设置了应用时销毁,除了Infinite 的GE都会销毁
	{
		Destroy();
	}
}

void AEffectActorBase::HandleOverlay(AActor* TargetActor)
{
	// 如果是敌人且不允许应用效果到敌人,则返回
	if (TargetActor->ActorHasTag("Enemy") && !bCanApplyEffectToEnemy)
	{
		return;
	}

	// 处理ApplyOnOverlap的GE
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		// 应用GE到 TargetActor
		ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);
	}

	if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);
	}

	if (InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		ApplyEffectToTarget(TargetActor, InfinityGameplayEffectClass);
	}
}

void AEffectActorBase::HandleEndOverlap(AActor* TargetActor)
{
	// 如果是敌人且不允许应用效果到敌人,则返回
	if (TargetActor->ActorHasTag("Enemy") && !bCanApplyEffectToEnemy)
	{
		return;
	}
	
	// ----------------------------------------------------------------------------------------------------------------
	//	处理ApplyOnEndOverlap的GE
	// ----------------------------------------------------------------------------------------------------------------

	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);
	}

	if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);
	}

	if (InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		ApplyEffectToTarget(TargetActor, InfinityGameplayEffectClass);
	}

	// ----------------------------------------------------------------------------------------------------------------
	//	移除Infinity的RemoveOnEndOverlap的GE
	// ----------------------------------------------------------------------------------------------------------------

	if (InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);

		if (!IsValid(TargetActor))
		{
			return;
		}

		TArray<FActiveGameplayEffectHandle> HandlesToRemove;

		for (TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandleTuple : ActiveEffectToRemove)
		{
			// 检查ASC是否相同
			if (TargetASC == HandleTuple.Value)
			{
				// 通过句柄将效果移除，注意，有可能有多层效果，不能将其它层的效果也移除掉，所以只移除一层
				TargetASC->RemoveActiveGameplayEffect(HandleTuple.Key, 1);
				//添加到移除列表
				HandlesToRemove.Add(HandleTuple.Key);
			}
		}

		for (auto& Handle : HandlesToRemove)
		{
			ActiveEffectToRemove.FindAndRemoveChecked(Handle);
		}
	}
}
